package org.lgiavedoni.android.franq.service.httpserver;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.velocity.VelocityContext;
import org.lgiavedoni.android.franq.service.log.Logger;
import org.lgiavedoni.android.franq.util.resource.ResourceUtil;
import org.lgiavedoni.android.franq.util.velocity.VelocityUtil;

public class ProcessClienteRequest extends Thread {
	private BufferedReader inFromClient;
	private DataOutputStream outToClient;
	private static final String PAGES_PATH = "httpService/";
	private final VelocityContext defaultContext = new VelocityContext();
	private final Socket connected;

	protected ProcessClienteRequest(Socket connected) {
		this.connected = connected;
		setName("HTTPServer [Processing client request]");
	}

	@Override
	public void run() {
		try {

			inFromClient = new BufferedReader(new InputStreamReader(connected.getInputStream()));
			outToClient = new DataOutputStream(connected.getOutputStream());

			String headerLine = inFromClient.readLine();
			if (headerLine != null) {
				StringTokenizer tokenizer = new StringTokenizer(headerLine);
				String httpMethod = tokenizer.nextToken();
				String httpQueryString = tokenizer.nextToken();

				if (httpMethod.equals("GET")) {
					doGet(httpQueryString);
				} else {
					sendResponse(404, "<b>The Requested resource not found ....");
				}
			}
		} catch (Exception e) {
			Logger.inst.warning(e.getMessage());
		}
	}

	private void doGet(String httpQueryString) throws Exception {
		if (httpQueryString.equals("/")) {
			// The default home page
			sendResponse(200, VelocityUtil.run(ResourceUtil.inst.getResource(PAGES_PATH + "home.html"), defaultContext));
		} else {
			// This is interpreted as a file name
			String page = httpQueryString.replaceFirst("/", "");

			// change thread name
			setName("HTTPServer Procession [" + page + "]");

			if (page.contains("?")) {
				page = page.substring(0, page.indexOf("?"));
			}

			Map<String, String> params = parseParameters(httpQueryString);
			File template = null;
			VelocityContext context = null;
			if (HTTPServerService.inst.getPages().containsKey(page)) {
				// load from controller
				template = ResourceUtil.inst.getResource(PAGES_PATH + HTTPServerService.inst.getPages().get(page).getTemplateName(params));
				context = HTTPServerService.inst.getPages().get(page).processRequest(defaultContext, params);
			} else {
				// load directly the file
				template = ResourceUtil.inst.getResource(PAGES_PATH + page);
				context = defaultContext;
			}
			if (template != null && template.exists())
				sendResponse(200, VelocityUtil.run(template, context));
			else
				sendResponse(404, "<b>The Requested resource not found ....");

		}
	}

	public Map<String, String> parseParameters(String url) {
		Map<String, String> parameters = new HashMap<String, String>();

		int i = url.indexOf("?");
		if (i > -1) {
			String searchURL = url.substring(url.indexOf("?") + 1);
			StringTokenizer st = new StringTokenizer(searchURL, "&");
			while (st.hasMoreTokens()) {
				String searchValue = st.nextToken();
				int j = searchValue.indexOf("=");
				parameters.put(searchValue.substring(0, j), searchValue.substring(j + 1));
			}
		}
		return parameters;
	}

	public void sendResponse(int statusCode, String responseString) throws Exception {
		try {

			String statusLine = null;
			String serverdetails = "Server: Java HTTPServer";
			String contentLengthLine = null;
			String contentTypeLine = "Content-Type: text/html" + "\r\n";

			if (statusCode == 200)
				statusLine = "HTTP/1.1 200 OK" + "\r\n";
			else
				statusLine = "HTTP/1.1 404 Not Found" + "\r\n";

			contentLengthLine = "Content-Length: " + responseString.length() + "\r\n";

			outToClient.writeBytes(statusLine);
			outToClient.writeBytes(serverdetails);
			outToClient.writeBytes(contentTypeLine);
			outToClient.writeBytes(contentLengthLine);
			outToClient.writeBytes("Connection: close\r\n");
			outToClient.writeBytes("\r\n");

			outToClient.writeBytes(responseString);
			outToClient.close();
		} catch (SocketException se) {
			/*
			 * Do nothing. This usually happen when the user stop the browser in
			 * the middle of a response
			 */
		}
	}

}
